<?php

namespace App\Models\ApiFilter;

use PHPUnit\Runner\Exception;

/**
 * Class ApiFilterBase
 * @package App\Models\ApiFilter
 */
class ApiFilterBase
{
    private static $modelDoc = [];
    private static $baseType = ['string', 'integer', 'double', 'boolean'];
    private static $compositeType = ['array', 'object'];

    public function __construct()
    {
        $fileList = scandir(dirname(__FILE__));
        $currently = basename(__FILE__);
        foreach ($fileList as $fileName) {
            if (in_array($fileName, ['.', '..', $currently])) {
                continue;
            }
            require __DIR__ . "/" . $fileName;
            $classNameStirng = "\App\Models\ApiFilter\\" . preg_replace('/^(.*)\.php/i', '$1', $fileName);
            new $classNameStirng();
        }
    }

    /**
     * 过滤$data，根据$model的规则，用于接口数据过滤
     *
     * @param $data
     * @param array|string $model array or "model:modelName"
     *
     * @return array|mixed [type]
     */
    public function filterData($data, $model)
    {
        if ('object' == gettype($data)) {
            if (method_exists($data, 'toArray')) {
                $data = $data->toArray();
            } else {
                $data = (array)$data;
            }
        }

        $return = [];
        if (is_null($model)) {
            $return = $data;
        } elseif (is_string($model)) {
            if (preg_match('/^model:([\d\w_-]+)$/', $model, $rs)) {
                if ($rs[1] == 'null') {
                    $return = $data;
                } else {
                    $modelObj = $this->getModel($rs[1]);
                    if ($modelObj) {
                        $return = $this->filterData($data, $this->getModel($rs[1]));
                    } else {
                        $this->error("model {$rs[1]} does not exists");
                    }
                }
            } elseif (preg_match('/^model:\[([\d\w_-]+)]$/', $model, $rs)) {
                if ($rs[1] == 'null') {
                    $return = $data;
                } elseif (in_array($rs[1], self::$baseType)) {
                    foreach ($data as $item) {
                        if (in_array(gettype($item), self::$compositeType)) {
                            continue;
                        }
                        $return[] = $item;
                    }
                } else {
                    $modelObj = $this->getModel($rs[1]);
                    if (!$modelObj) {
                        $this->error("Model {$rs[1]} does not exists");
                    }
                    foreach ($data as $item) {
                        if ($item == null) {
                            continue;
                        }
                        $return[] = $this->filterData($item, $modelObj);
                    }
                }
            } else {
                $this->error($model . "是错误的语法，正确写法：'model:modelName'或'model:[modelName]'");
            }
        } elseif (is_array($model) && is_array($data)) {
            foreach ($model as $k => $v) {
                if (is_array($v)) {
                    if (!isset($data[$k])) {
                        continue;
                    } else {
                        $return[$k] = $this->filterData($data[$k], $v);
                    }
                } elseif (is_integer($k)) {
                    if (array_key_exists($v, $data)) {
                        if ($data[$v] === null) {
                            $return[$v] = null;
                        } elseif (!in_array(gettype($data[$v]), self::$compositeType)) {
                            $return[$v] = $data[$v];
                        }
                    }
                } elseif (is_array($data) && array_key_exists($k, $data)) {
                    $return[$k] = $this->filterData($data[$k], $v);
                } else {
                }
            }
        }
        return $return;
    }

    /**
     * @param string $msg
     */
    private function error($msg)
    {
        if ('local' == config('app.env')) {
            dd($msg);
        } else {
            throw new Exception($msg);
        }
    }

    /**
     * @param string $name  模块名
     * @param array  $model 模块结构
     *
     * @return void
     */
    protected function addModel(string $name, array $model): void
    {
        if (isset(ApiFilterBase::$modelDoc[$name])) {
            $this->error('Model ' . $name . ' already exists');
        }
        ApiFilterBase::$modelDoc[$name] = $model;
    }

    /**
     * @param string $name 模块名
     *
     * @return mixed|null
     */
    protected function getModel(string $name)
    {
        return ApiFilterBase::$modelDoc[$name] ?? null;
    }
}
